package edu.ustb.mis.excel.utils;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import edu.ustb.mis.dm.util.NullHandlerUtils;
import edu.ustb.mis.excel.annotation.Excel;

public class ExcelImporter<T> {
	Class<T> clazz;

	public ExcelImporter(final Class<T> clazz) {
		this.clazz = clazz;
	}

	public Collection<T> importExcel(final File file, final String excelType, final String... pattern) throws Exception {
		final Collection<T> dist = Lists.newArrayList();
		/**
		 * 类反射得到调用方法
		 */
		// 得到目标目标类的所有的字段列表
		final Field filed[] = clazz.getDeclaredFields();
		// 将所有标有Annotation的字段，也就是允许导入数据的字段,放入到一个map中
		final Map<String, Method> fieldmap = Maps.newHashMap();
		// 循环读取所有字段
		for (final Field f : filed) {
			// 得到单个字段上的Annotation
			final Excel exa = f.getAnnotation(Excel.class);
			// 如果标识了Annotationd的话
			if (exa != null) {
				// 构造设置了Annotation的字段的Setter方法
				final String fieldname = f.getName();
				final String setMethodName = "set" + fieldname.substring(0, 1).toUpperCase() + fieldname.substring(1);
				// 构造调用的method，
				final Method setMethod = clazz.getMethod(setMethodName, new Class[]{f.getType()});
				// 将这个method以Annotaion的名字为key来存入。
				fieldmap.put(exa.exportName(), setMethod);
			}
		}
		/**
		 * excel的解析开始
		 */
		// 将传入的File构造为FileInputStream;
		final FileInputStream in = new FileInputStream(file);
		// // 得到工作表
		final Workbook book = excelType.equals("2003") ? new HSSFWorkbook(in) : new XSSFWorkbook(in);
		// // 得到第一页
		final Sheet sheet = book.getSheetAt(0);
		// // 得到第一面的所有行
		final Iterator<Row> row = sheet.rowIterator();
		/**
		 * 标题解析
		 */
		// 得到第一行，也就是标题行
		final Row title = row.next();
		// 得到第一行的所有列
		final Iterator<Cell> cellTitle = title.cellIterator();
		// 将标题的文字内容放入到一个map中。
		final Map<Integer, String> titlemap = Maps.newHashMap();
		// 从标题第一列开始
		int i = 0;
		// 循环标题所有的列
		while (cellTitle.hasNext()) {
			final Cell cell = cellTitle.next();
			final String value = cell.getStringCellValue();
			titlemap.put(i, value);
			i = i + 1;
		}
		/**
		 * 解析内容行
		 */
		// 用来格式化日期的DateFormat
		SimpleDateFormat sf;
		if (pattern.length < 1) {
			sf = new SimpleDateFormat("yyyy-MM-dd");
		} else {
			sf = new SimpleDateFormat(pattern[0]);
		}
		while (row.hasNext()) {
			// 标题下的第一行
			final Row rown = row.next();
			// 行的所有列
			final Iterator<Cell> cellbody = rown.cellIterator();
			// 得到传入类的实例
			final T tObject = clazz.newInstance();
			int k = 0;
			// 遍历一行的列
			while (cellbody.hasNext()) {
				final Cell cell = cellbody.next();
				// 这里得到此列的对应的标题
				final String titleString = titlemap.get(k);
				// 如果这一列的标题和类中的某一列的Annotation相同，那么则调用此类的的set方法，进行设值
				if (fieldmap.containsKey(titleString)) {
					final Method setMethod = fieldmap.get(titleString);
					// 得到setter方法的参数
					final Type[] ts = setMethod.getGenericParameterTypes();
					// 只要一个参数
					final String xclass = ts[0].toString();
					// 判断参数类型
					if (xclass.equals("class java.lang.String")) {
						setMethod.invoke(tObject, cell.getStringCellValue());
					} else if (xclass.equals("class java.util.Date")) {
						setMethod.invoke(tObject, sf.parse(cell.getStringCellValue()));
					} else if (xclass.equals("class java.lang.Boolean")) {
						Boolean boolname = true;
						if (cell.getStringCellValue().equals("否")) {
							boolname = false;
						}
						setMethod.invoke(tObject, boolname);
					} else if (xclass.equals("class java.lang.Integer")) {
						setMethod.invoke(tObject, NullHandlerUtils.NullToIneger(Double.valueOf(cell.getNumericCellValue()).intValue()));
					} else if (xclass.equals("class java.lang.Long")) {
						setMethod.invoke(tObject, new Long((long)cell.getNumericCellValue()));
					} else if (xclass.equals("class java.lang.Double")) {
						setMethod.invoke(tObject, NullHandlerUtils.NullToDouble(cell.getNumericCellValue()));
					}
				}
				// 下一列
				k = k + 1;
			}
			dist.add(tObject);
		}
		in.close();
		return dist;
	}
}
